home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / apps / 453 / rtxqio.c < prev    next >
C/C++ Source or Header  |  1990-02-16  |  10KB  |  403 lines

  1. #include <stdio.h>
  2. #include <osbind.h>
  3. #include <tosdefs.h>
  4. #include <rtxbind.h>
  5. #include "rtxqio.h"
  6.  
  7. /*
  8.  * RTXQIO - Queued (Asynchronous) I/O Library
  9.  *
  10.  * Description:
  11.  *    This code implements Queued, asynchronous I/O
  12.  *    under Micro RTX (tm) for those operating
  13.  *    system hackers that like this style of
  14.  *    I/O processing.  QIO comes from a famous
  15.  *    operating system which shall remain nameless.
  16.  *
  17.  *    It demonstrates the types of facilities that
  18.  *    can be implemented on top of RTX, and is
  19.  *    really just a skeleton for a more complete
  20.  *    implementation.
  21.  *
  22.  *    The mechanism works like this: I/O requests
  23.  *    are queued on a QIO channel, and then serviced
  24.  *    in FIFO order by an asychronous server process.
  25.  *    Once the I/O request is queued, the requesting
  26.  *    process may continue with other processing.
  27.  *
  28.  *    Internally, the implementation does it by creating
  29.  *    a server process for each QIO channel, along with
  30.  *    two RTX message queues.  When a process queues an
  31.  *    I/O request, it builds an I/O request packet, and
  32.  *    sends it over an RTX Queue to the appropriate
  33.  *    server process.  When the process wishes to
  34.  *    synchonize with the completion of the I/O request,
  35.  *    it simply waits for a message back from the
  36.  *    server.
  37.  *
  38.  *    The server process and RTX queues ares created
  39.  *    dynamically as QIO channels are needed.  Likewise,
  40.  *    they are deleted when a QIO channel is closed.
  41.  *
  42.  *    I've always thought the QIO scheme was a screwy way
  43.  *    to do things.  But you asked for it.
  44.  *
  45.  */
  46.  
  47. /*
  48.  * function to get an I/O request Packet from a message queue
  49.  */
  50. struct qio_request *get_iorp(msgq)
  51. char *msgq;
  52. {
  53.     struct qio_msg msg;
  54.  
  55.     /* get next queued I/O request (wait forever) */
  56.     if (q_req(msgq, &msg, 0, 0L))
  57.         return(0);            /* failure */
  58.     /* validate iorp message */
  59.     if (msg.iorp_valid != IORP_VALID)
  60.         return(0);            /* failure */
  61.     return(msg.iorp);
  62. }
  63.  
  64.  
  65. /*
  66.  * Here is the server process.  One incarnation of this process
  67.  * exists for each QIO channel, therefore it must be reentrant.
  68.  */
  69. static server(channel)
  70. struct qio_channel *channel;        /* channel */
  71. {
  72.     struct qio_request *iorp;
  73.     int operation;
  74.     struct qio_msg msg;
  75.  
  76.     /* loop until DELETE message received */
  77.     do {
  78.         /* get next queued I/O request */
  79.         if (q_req(channel->serverq, &msg, 0, 0L))
  80.             continue;
  81.         /* validate iorp message */
  82.         if (msg.iorp_valid != IORP_VALID)
  83.             continue;
  84.         iorp = msg.iorp;
  85.         /* perform requested operation */
  86.         switch (operation = iorp->operation) {
  87.         case QIO_FOPEN:
  88.             iorp->retcode = Fopen(iorp->buffer, iorp->handle);
  89.             break;
  90.  
  91.         case QIO_FCLOSE:
  92.             iorp->retcode = Fclose(iorp->handle);
  93.             break;
  94.  
  95.         case QIO_FREAD:
  96.             iorp->retcode = Fread(iorp->handle, 
  97.                               iorp->count, iorp->buffer);
  98.             break;
  99.  
  100.         case QIO_FWRITE:
  101.             iorp->retcode = Fwrite(iorp->handle, 
  102.                               iorp->count, iorp->buffer);
  103.             break;
  104.  
  105.         case QIO_DELETE:
  106.             /* terminate */
  107.             iorp->retcode = 0;
  108.             break;
  109.  
  110.         /* add your own options here */
  111.  
  112.         default:
  113.             /* Invalid Function */
  114.             iorp->retcode = EINVFN;
  115.             break;
  116.         }
  117.         /* send the IO request back to requestor */
  118.         q_send(channel->replyq, &msg);
  119.  
  120.     } while (operation != QIO_DELETE);
  121.     p_delete((char *)0);
  122. }
  123.  
  124.  
  125. /*
  126.  * This function "opens" a QIO channel by creating a server process
  127.  * and the associated message queues.
  128.  */
  129. struct qio_channel *qio_open(name)
  130. char *name;
  131. {
  132.     struct qio_channel *channel;    /* stack channel for p_create */
  133.     int dummy;            /* dummy integer */
  134.     char namebuf[16];        /* name buffer for q_create */
  135.  
  136.  
  137.     /* get a buffer for the "channel" data structure */
  138.     if ((channel = m_alloc((long)sizeof(struct qio_channel))) != 0) {
  139.         /* create RTX message Q for QIO serverq */
  140.         strcpy(namebuf, "SQ_");
  141.         strcat(namebuf, name);
  142.         if ((channel->serverq = q_create(namebuf, 0)) == 0) {
  143.             m_free(channel);
  144.             return(0);    /* fail */
  145.         }
  146.         /* create RTX message Q for QIO replyq */
  147.         strcpy(namebuf, "RQ_");
  148.         strcat(namebuf, name);
  149.         if ((channel->replyq = q_create(namebuf, 0)) == 0) {
  150.             q_delete(channel->serverq);
  151.             m_free(channel);
  152.             return(0);    /* fail */
  153.         }
  154.         /* spawn a copy of the server process */
  155.         if (p_create(name, 
  156.             p_priority(0, (char *)0),
  157.             p_slice(0, (char *)0),
  158.             server,
  159.             sizeof(int *), 
  160.             &channel,
  161.             4096L) == 0) {    /* failure if couldn't create */
  162.             q_delete(channel->serverq);
  163.             q_delete(channel->replyq);
  164.             m_free(channel);
  165.             return(0);    /* fail */
  166.         }
  167.     }
  168.     return(channel);        /* return channel address to caller */
  169. }
  170.  
  171.  
  172. /*
  173.  * This function queues an I/O request. It builds an I/O Request Packet
  174.  * and sends it to the server.
  175.  *
  176.  * The parameters passed in the I/O Request Packet (IORP) are sent
  177.  * to the server untouched, so they really cound be used for anything.
  178.  * The server validates the parameters, and caries out the specified
  179.  * operation. This function simply sends the request to the server.
  180.  */
  181. qio_start(channel, operation, handle, buffer, count)
  182. struct qio_channel *channel;
  183. int operation;
  184. int handle;
  185. char *buffer;
  186. long count;
  187. {
  188.     struct qio_request *iorp;
  189.     struct qio_msg msg;
  190.  
  191.     /* build the IO request packet */
  192.     if ((iorp = m_alloc((long)sizeof(struct qio_request))) == 0) {
  193.         return(-1);        /* failure */
  194.     }
  195.     /* load the QIO request parameters */
  196.     iorp->operation = operation;        /* opcode */
  197.     iorp->handle = handle;            /* handler parameter */
  198.     iorp->buffer = buffer;            /* buffer address */
  199.     iorp->count = count;            /* count */
  200.     msg.iorp = iorp;            /* message addresses IORP */
  201.     msg.iorp_valid = IORP_VALID;        /* Indicate message type */
  202.     /* send the IO request to the server */
  203.     if (q_send(channel->serverq, &msg)) {
  204.         m_free(iorp);        
  205.         return(-1);        /* fail */
  206.     }
  207.     return(0);            /* success */
  208. }
  209.  
  210. /*
  211.  * This function returns the completion of the specified I/O request.
  212.  * The value returned corresponds to the valid return values for the
  213.  * given class of operation.
  214.  *
  215.  * This is how the requesting process synchronizes with the queued
  216.  * I/O operation.  Replys come back in the same order that they were
  217.  * send out via the qio_start() service. If you are expecting a
  218.  * reply out of order, you'll have a long wait (forever).
  219.  */
  220. long qio_stop(channel)
  221. struct qio_channel *channel;
  222. {
  223.     struct qio_request *iorp;
  224.     long retcode;
  225.  
  226.     /* wait for next I/O Completion */
  227.     if ((iorp = get_iorp(channel->replyq)) == 0)
  228.         return(-1);            /* failure */
  229.     retcode = iorp->retcode;        /* get return code */
  230.     m_free(iorp);                /* free the IO packet */
  231.     return(retcode);            /* return return code */
  232. }
  233.  
  234.  
  235. /*
  236.  * This function "closes" a QIO channel by sending a "DELETE"
  237.  * message to the server, and waiting for the reply. This is
  238.  * necessary to rundown any pending I/O operations.  When
  239.  * all outstanding I/O is complete, the message queue and
  240.  * associated data structures are deleted.
  241. */
  242. qio_close(channel)
  243. struct qio_channel *channel;
  244. {
  245.     struct qio_request *iorp;
  246.     struct qio_msg msg;
  247.  
  248.     if ((iorp = m_alloc((long)sizeof(struct qio_request))) == 0) {
  249.         return(0);
  250.     }
  251.     iorp->operation = QIO_DELETE;
  252.     msg.iorp = iorp;
  253.     msg.iorp_valid = IORP_VALID;
  254.     if (q_send(channel->serverq, &msg)) {
  255.         m_free(iorp);
  256.         return(-1);        /* failure */
  257.     }
  258.  
  259.     /* Wait for all I/O completions */
  260.     do {
  261.         if ((iorp = get_iorp(channel->replyq)) == 0)
  262.             break;
  263.     } while (iorp->operation != QIO_DELETE);
  264.  
  265.     /* delete the message queues */
  266.     q_delete(channel->serverq);
  267.     q_delete(channel->replyq);
  268.     /* free the "channel" data structure */
  269.     m_free(channel);
  270.     return(0);
  271. }
  272. /**************** END OF QIO LIBRARY **************************************/
  273.  
  274. /**************************************************************************
  275.  *
  276.  *  The following is just sample code to show how the above functions
  277.  *  may be used in your programs.
  278.  *
  279.  **************************************************************************/
  280.  
  281. #define BUFSIZE 1024
  282. char buf1[BUFSIZE];            /* buffer for reading */
  283.  
  284.  
  285. extern char *_base;            /* GEMDOS basepage */
  286.  
  287. /*
  288.  * start_read - start a QIO read
  289.  */
  290. start_read(chan, han, buf)
  291. struct qio_channel *chan;
  292. int han;
  293. char *buf;
  294. {
  295.     int i;
  296.     long retcode;
  297.         
  298.     if (qio_start(chan, QIO_FREAD, han, buf, (long)BUFSIZE)) {
  299.         fprintf(stderr, "failed qio_start\n");
  300.         exit(1);
  301.     }
  302. }
  303.  
  304.  
  305. /*
  306.  * open_file - open a file using the QIO services
  307.  */
  308. open_file(chan, name)
  309. struct qio_channel *chan;
  310. char *name;
  311. {
  312.     int i;
  313.     long retcode;
  314.         
  315.     if (qio_start(chan, QIO_FOPEN, 0, name, 0L)) {
  316.         fprintf(stderr, "open_file: failed qio_start\n");
  317.         exit(1);
  318.     }
  319.     retcode = qio_stop(chan);
  320.     printf("open_file: I/O Complete, retcode=%ld\n", retcode);
  321.     return((int)retcode);
  322. }
  323.  
  324. /*
  325.  * close_file - close file using QIO services
  326.  */
  327. close_file(chan, han)
  328. struct qio_channel *chan;
  329. int han;
  330. {
  331.     int i;
  332.     long retcode;
  333.         
  334.     if (qio_start(chan, QIO_FCLOSE, han, (char *)0, 0L)) {
  335.         fprintf(stderr, "close_file: failed qio_start\n");
  336.         exit(1);
  337.     }
  338.     retcode = qio_stop(chan);
  339.     printf("close_file: I/O Complete, retcode=%ld\n", retcode);
  340.     return((int)retcode);
  341. }
  342.  
  343. /*
  344.  * The main routine.
  345.  */
  346. main(argc, argv)
  347. int argc;
  348. char *argv[];
  349. {
  350.     struct qio_channel *chan1;
  351.     int han1;
  352.     struct config config;
  353.  
  354.     /* configuratioin table */
  355.     config.basepage = _base;
  356.     config.max_proc = 32;
  357.     config.max_msgs = 200;
  358.     config.max_queues = 10;
  359.     config.create_call = 0L;
  360.     config.delete_call = 0L;
  361.     config.switch_call = 0L;
  362.  
  363.     /* install the MICRO RTX kernel */
  364.     rtx_install(&config);
  365.  
  366.  
  367.     /* always reads a specified file */
  368.     if (argc != 2) {
  369.         printf("usage: qiotest file\n");
  370.         exit(1);
  371.     }
  372.  
  373.     /* open a QIO channel */
  374.     if ((chan1 = qio_open("Chan1")) == 0) {
  375.         fprintf(stderr, "failed qio_open\n");
  376.         exit(1);
  377.     }
  378.     printf("QIO channel %08lx open\n", chan1);
  379.  
  380.     /* open the specified file */
  381.     han1 = open_file(chan1, argv[1]);
  382.  
  383.     /* loop reading blocks from the file */
  384.     do {
  385.         /* Queue the I/O request */
  386.         start_read(chan1, han1, buf1);
  387.         
  388.         /* Do other processing, asynchronously */
  389.         printf("I/O Operation Queued. Doing some other stuff now.\n");
  390.  
  391.     } while (qio_stop(chan1) > 0); /* synchronize */
  392.  
  393.     /* close the file */
  394.     close_file(chan1, han1);
  395.  
  396.     /* close the QIO channel */
  397.     qio_close(chan1);
  398.     printf("QIO channel %08lx closed\n", chan1);
  399.  
  400.     /* All done */
  401.     rtx_remove();
  402. }
  403.